package service

import (
	"context"
	"sale-admin/config/mysql"
	"sale-admin/internal/app/grpc/client"
	"sale-admin/internal/app/grpc/protoc/devicec"
	"sale-admin/internal/app/grpc/protoc/system_admin"
	"sale-admin/internal/app/web/service/common"
	"sale-admin/internal/dal"
	"sale-admin/internal/dao"
	"sale-admin/internal/models"
	"strconv"
	"strings"

	"192.168.1.75/go-pkg/logx"
	"github.com/golang-module/carbon/v2"
	"github.com/samber/lo"
	"gorm.io/gorm"
)

type GoodsDailyReport struct{}

// 填充数据
func (GoodsDailyReport) FixData(totalStart, totalEnd int64) {
	// 订单信息
	GoodsDailyReport{}.FixGoodsOrder(totalStart, totalEnd)
	// 商品点击量
	GoodsDailyReport{}.FixGoodsClick(totalStart, totalEnd)
}

// 商品点击量
func (GoodsDailyReport) FixGoodsClick(totalStart, totalEnd int64) {
	ctx := context.Background()
	db := mysql.NewDB()
	for i := totalStart; i < totalEnd; i += 86400 {
		date := carbon.CreateFromTimestamp(i).ToDateString()
		dailyRobotList, robotCount, _ := dao.Robot{}.RobotList(ctx, db, "", date, "", "", "", "", "", "")
		if robotCount == 0 {
			continue
		}
		for _, robot := range dailyRobotList {
			GoodsDailyReport{}.UpdateGoodsClick(ctx, db, robot.RobotName, "", date)
		}
	}
}

// 填充订单信息
func (GoodsDailyReport) FixGoodsOrder(totalStart, totalEnd int64) {
	ctx := context.Background()
	db := mysql.NewDB()

	for i := totalStart; i < totalEnd; i += 86400 {
		date := carbon.CreateFromTimestamp(i).ToDateString()
		// 处理订单
		orderList, _ := dao.NewOrder(ctx, dal.Q).WithDateCond(date).List()
		if len(orderList) > 0 {
			goodsIDs := []string{}
			for _, record := range orderList {
				goodsIDs = append(goodsIDs, record.GoodsID)
			}
			goodsIDs = lo.Uniq(goodsIDs)
			detailMap := dao.Goods{}.DetailMap(context.Background(), dal.Q, goodsIDs)
			for _, v := range detailMap {
				GoodsDailyReport{}.UpdateOrder(ctx, db, v.GoodsID, v.GoodsName1, date)
			}
		}
		// 处理退款
		// 查询所有退款订单
		refundList, _ := dao.OrderRefund{}.OrderRefundList(ctx, db, "", date)
		if len(refundList) > 0 {
			var endOutTradeNos []string
			// v.OutTradeNo是带后缀的订单号
			for _, v := range refundList {
				if !lo.Contains(endOutTradeNos, v.OutTradeNo) {
					endOutTradeNos = append(endOutTradeNos, v.OutTradeNo)
				}
			}
			if len(endOutTradeNos) > 0 {
				// end_out_trade_no 转 out_trade_no
				var goodsIDs []string
				db.Model(&models.MaOrder{}).
					Where("end_out_trade_no in ?", endOutTradeNos).
					Pluck("goods_id", &goodsIDs)
				if len(goodsIDs) > 0 {
					detailMap := dao.Goods{}.DetailMap(context.Background(), dal.Q, goodsIDs)
					for _, v := range detailMap {
						GoodsDailyReport{}.UpdateOrderRefund(ctx, db, v.GoodsID, v.GoodsName1, date)
					}
				}
			}
		}
	}
}

// 更新订单信息
func (GoodsDailyReport) UpdateOrder(ctx context.Context, db *gorm.DB, goodsID, goodsName, date string) {
	date = carbon.Parse(date).ToDateString()
	// 今日订单统计数据
	RobotOrderList, _ := dao.NewOrder(ctx, dal.Q).WithDateCond(date).WithGoodsIDCond([]string{goodsID}).RobotOrderOverview()
	var repeatUserTotal dao.TotalPaidUser
	if len(RobotOrderList) != 0 {
		repeatUserTotal, _ = dao.WechatRate{}.GetDailyRepeatUser(ctx, db, "", goodsID, date)
	}
	for _, order := range RobotOrderList {
		if order.Areas1 == "" {
			order.Areas1 = "0"
		}
		if order.Areas2 == "" {
			order.Areas2 = "0"
		}
		if order.Areas3 == "" {
			order.Areas3 = "0"
		}
		provinceID := order.Areas1
		cityID := order.Areas2
		locationID := order.Areas3
		// 从订单中获取商户id
		r := dao.NewGoodsDailyReport(ctx, db)
		dao.GoodsDailyReport{}.Save(ctx, db, order.MerchantID, goodsID, goodsName, order.RobotName, date,
			provinceID, cityID, locationID,
			r.WithGMV(order.GMV),
			r.WithPaymentAmount(order.PaymentAmount),
			r.WithTransactionAmount(order.TransactionAmount),
			r.WithTotalPaidOrder(order.TotalPaidOrder),
			r.WithDiscountAmount(order.DiscountAmount),
			r.WithGiveAmount(order.GiveAmount),
			r.WithTotalOrder(order.TotalOrder),
			r.WithTotalNotPaidOrder(order.TotalNotPaidOrder),
			r.WithTotalPaidUser(repeatUserTotal.PayNum),
		)
	}
}

// 商品日报表更新退款信息
func (GoodsDailyReport) UpdateOrderRefund(ctx context.Context, db *gorm.DB, goodsID, goodsName, date string) {
	date = carbon.Parse(date).ToDateString()
	// 退款
	robotRefundList, _ := dao.OrderRefund{}.OrderRefundListByGoods(ctx, db, goodsID, date)
	if len(robotRefundList) > 0 {
		var RobotRefundTotal = make(map[string]struct {
			dao.RefundStruct
			MerchantID string
			ProvinceID string
			CityID     string
			LocationID string
		})
		for _, refundInfo := range robotRefundList {
			RefundOrderCount := RobotRefundTotal[refundInfo.RobotName].RefundOrderCount
			RefundOrderCount += refundInfo.RefundOrderCount
			RefundOrderAmount := RobotRefundTotal[refundInfo.RobotName].RefundOrderAmount
			RefundOrderAmount += refundInfo.RefundOrderAmount
			robotRefundItem := dao.RefundStruct{
				RobotName:         refundInfo.RobotName,
				RefundOrderCount:  RefundOrderCount,  // 按机器汇总退款订单数
				RefundOrderAmount: RefundOrderAmount, // 按机器汇总退款金额
			}

			// 查询订单信息
			if strings.Contains(refundInfo.OutTradeNo, "P") {
				refundInfo.OutTradeNo = strings.TrimSuffix(refundInfo.OutTradeNo, "P")
			} else if strings.Contains(refundInfo.OutTradeNo, "F") {
				refundInfo.OutTradeNo = strings.Split(refundInfo.OutTradeNo, "F")[0]
			}
			orderInfo, _ := dao.NewOrder(ctx, dal.Q).WithOutTradeNoCond(refundInfo.OutTradeNo).OrderDetail()
			RobotRefundTotal[refundInfo.RobotName] = struct {
				dao.RefundStruct
				MerchantID string
				ProvinceID string
				CityID     string
				LocationID string
			}{
				RefundStruct: robotRefundItem,
				MerchantID:   orderInfo.MerchantID,
				ProvinceID:   strconv.Itoa(orderInfo.Areas1),
				CityID:       strconv.Itoa(orderInfo.Areas2),
				LocationID:   strconv.Itoa(orderInfo.Areas3),
			}
		}
		for _, v := range RobotRefundTotal {
			r := dao.NewGoodsDailyReport(ctx, db)
			dao.GoodsDailyReport{}.Save(ctx, db, v.MerchantID, goodsID, goodsName, v.RobotName, date,
				v.ProvinceID, v.CityID, v.LocationID,
				r.WithRefundAmount(v.RefundOrderAmount),
				r.WithTotalRefundOrder(v.RefundOrderCount),
			)
		}
	}
}

// 商品运营日报更新商品点击量
func (GoodsDailyReport) UpdateGoodsClick(ctx context.Context, db *gorm.DB, robotName, goodsID, date string) {
	date = carbon.Parse(date).ToDateString()

	// 查询机器信息
	robotInfo, _ := dao.Robot{}.RobotDetail(ctx, db, "", robotName, "")
	if robotInfo == nil || robotInfo.ID == "" {
		return
	}
	goodsClickTotal, _ := dao.GoodsClick{}.GetDailyGoodsClick(ctx, db, robotName, goodsID, date)
	for _, v := range goodsClickTotal {
		if v.ClickNum != 0 {
			var goodsName string
			db.Model(&models.MaGoodsInfo{}).
				Where("goods_id = ?", v.GoodsID).
				Select("goods_name1").
				Take(&goodsName)
			provinceID := strconv.Itoa(robotInfo.Areas1)
			cityID := strconv.Itoa(robotInfo.Areas2)
			locationID := strconv.Itoa(robotInfo.Areas3)
			r := dao.NewGoodsDailyReport(ctx, db)
			dao.GoodsDailyReport{}.Save(ctx, db, robotInfo.MerchantID, v.GoodsID, goodsName, robotInfo.RobotName, date,
				provinceID, cityID, locationID,
				r.WithTotalGoodsClick(v.ClickNum),
			)
		}
	}
}

// 获取统计数据
func (GoodsDailyReport) DailyReport(ctx context.Context, loginMerchantID string, startTime, endTime int64, merchantIDs, goodsID, goodsName,
	robotID, locationID, cityID string, groupType int, orderType string, summaryType int, page, limit int,
) (data []*models.GoodsDailyReport, count int64, summary *models.GoodsDailyReport, err error) {
	db := mysql.NewDB()

	validMerchantIDs, err := common.Order{}.GetMerchantChildren(ctx, loginMerchantID, strings.Split(merchantIDs, ","))
	if err != nil {
		return data, count, nil, err
	}

	list, count, sum, err := dao.NewGoodsDailyReport(ctx, db).
		WithTimePeriod(startTime, endTime).
		WithGoodsID(goodsID).
		WithRobotID(robotID).
		WithGoodsName(goodsName).
		WithMerchantID(strings.Join(validMerchantIDs, ",")).
		WithLocationID(locationID).
		WithCityID(cityID).
		WithOrderType(orderType).
		WithGroupType(groupType).
		WithSummary(summaryType).
		WithPaginate(page, limit).
		List()
	if list == nil {
		return []*models.GoodsDailyReport{}, 0, summary, err
	}
	if summaryType != 0 {
		summary = sum
	}

	// 系统后台grpc
	SystemAdminClient, systemcClientErr := client.GetSystemAdminClient()
	if systemcClientErr != nil {
		logx.Error(ctx, "connect system admin grpc error", logx.Any("err", systemcClientErr.Error()))
		return
	}
	// 设备后台grpc
	DeviceAdminClient, deviceClientErr := client.GetDeviceAdminClient()
	if deviceClientErr != nil {
		logx.Error(ctx, "connect device admin grpc error", logx.Any("err", deviceClientErr.Error()))
		return
	}

	var areas []string
	var locations []string
	for _, v := range list {
		if v.ProvinceID != nil {
			if !lo.Contains(areas, *v.ProvinceID) {
				areas = append(areas, *v.ProvinceID)
			}
		}
		if v.CityID != nil {
			if !lo.Contains(areas, *v.CityID) {
				areas = append(areas, *v.CityID)
			}
		}
		if v.LocationID != nil {
			if !lo.Contains(locations, *v.LocationID) {
				locations = append(locations, *v.LocationID)
			}
		}
	}
	var areaNameMap = make(map[string]string)
	if len(areas) > 0 {
		var req system_admin.AreaNameReq
		req.AreaIds = areas
		res, err1 := SystemAdminClient.AreaName(ctx, &req)
		if err1 != nil {
			logx.Error(ctx, "get area error", logx.Any("res", res), logx.Any("err", err1.Error()))
			return
		}
		areaNameMap = res.AreaNameMap
	}
	var locationNameMap = make(map[string]string)
	if len(locations) > 0 {
		var req devicec.LocationNameReq
		req.LocationIds = locations
		res, err1 := DeviceAdminClient.LocationName(ctx, &req)
		if err1 != nil {
			logx.Error(ctx, "get location error", logx.Any("res", res), logx.Any("err", err1.Error()))
			return
		}
		locationNameMap = res.LocationNameMap
	}
	var MerchantIDList []string
	for k, v := range list {
		if v.MerchantID != nil {
			if !lo.Contains(MerchantIDList, *v.MerchantID) {
				MerchantIDList = append(MerchantIDList, *v.MerchantID)
			}
		}
		// 支付率 = 支付量/下单量
		if v.TotalOrder != nil {
			var paidRatio float64
			if *v.TotalOrder != 0 && v.TotalPaidOrder != nil {
				paidRatio = common.Decimal(float64(*v.TotalPaidOrder)/float64(*v.TotalOrder), 4)
			}
			list[k].PaidRatio = &paidRatio
		}
		// 创单率 = 下单量/点击量
		if v.TotalGoodsClick != nil {
			var createOrderRatio float64
			if *v.TotalGoodsClick != 0 && v.TotalOrder != nil {
				createOrderRatio = common.Decimal(float64(*v.TotalOrder)/float64(*v.TotalGoodsClick), 4)
			}
			list[k].CreateOrderRatio = &createOrderRatio
		}
		// 退款率 = 退款量/(支付量+退款量)
		if v.TotalPaidOrder != nil {
			var refundRatio float64
			if *v.TotalPaidOrder != 0 && v.TotalRefundOrder != nil {
				refundRatio = common.Decimal(float64(*v.TotalRefundOrder)/(float64(*v.TotalPaidOrder)+float64(*v.TotalRefundOrder)), 4)
			}
			list[k].RefundRatio = &refundRatio
		}
		if v.TransactionAmount != nil && v.RefundAmount != nil {
			paymentAmount := common.Decimal(*v.TransactionAmount-*v.RefundAmount, 4)
			list[k].PaymentAmount = &paymentAmount
		}
		if v.ProvinceID != nil && len(areaNameMap) > 0 {
			if _, ok := areaNameMap[*v.ProvinceID]; ok {
				province := areaNameMap[*v.ProvinceID]
				list[k].Province = &province
			} else if *v.ProvinceID == "0" {
				province := ""
				list[k].Province = &province
			}
		}
		if v.CityID != nil && len(areaNameMap) > 0 {
			if _, ok := areaNameMap[*v.CityID]; ok {
				city := areaNameMap[*v.CityID]
				list[k].City = &city
			} else if *v.CityID == "0" {
				city := ""
				list[k].City = &city
			}
		}
		if v.LocationID != nil && len(locationNameMap) > 0 {
			if _, ok := locationNameMap[*v.LocationID]; ok {
				location := locationNameMap[*v.LocationID]
				list[k].Location = &location
			} else if *v.LocationID == "0" {
				location := ""
				list[k].Location = &location
			}
		}
	}

	merchantReq := &system_admin.MerchantNameReq{
		MerchantIds: MerchantIDList,
	}
	merchantNameMapRes, err1 := SystemAdminClient.MerchantName(ctx, merchantReq)
	if err1 != nil {
		return
	}
	for k, v := range list {
		if v.MerchantID != nil {
			if merchantNameMapRes != nil && merchantNameMapRes.MerchantNameMap != nil {
				if _, ok := merchantNameMapRes.MerchantNameMap[*v.MerchantID]; ok {
					merchantName := merchantNameMapRes.MerchantNameMap[*v.MerchantID]
					list[k].MerchantName = &merchantName
				}
			}
		}
	}
	if summaryType == 1 {
		// 订单
		// 支付率 = 支付量/下单量
		if summary.TotalOrder != nil {
			var paidRatio float64
			if *summary.TotalOrder != 0 && summary.TotalPaidOrder != nil {
				paidRatio = common.Decimal(float64(*summary.TotalPaidOrder)/float64(*summary.TotalOrder), 4)
			}
			summary.PaidRatio = &paidRatio
		}
		// 创单率 = 下单量/点击量
		if summary.TotalGoodsClick != nil {
			var createOrderRatio float64
			if *summary.TotalGoodsClick != 0 && summary.TotalOrder != nil {
				createOrderRatio = common.Decimal(float64(*summary.TotalOrder)/float64(*summary.TotalGoodsClick), 4)
			}
			summary.CreateOrderRatio = &createOrderRatio
		}
		// 退款率 = 退款量/(支付量+退款量)
		if summary.TotalPaidOrder != nil {
			var refundRatio float64
			if *summary.TotalPaidOrder != 0 && summary.TotalRefundOrder != nil {
				refundRatio = common.Decimal(float64(*summary.TotalRefundOrder)/(float64(*summary.TotalPaidOrder)+float64(*summary.TotalRefundOrder)), 4)
			}
			summary.RefundRatio = &refundRatio
		}
		if summary.TransactionAmount != nil && summary.RefundAmount != nil {
			paymentAmount := common.Decimal(*summary.TransactionAmount-*summary.RefundAmount, 4)
			summary.PaymentAmount = &paymentAmount
		}
	}
	return list, count, summary, err
}
